/*
 * Created by SharpDevelop.
 * User: EdwardW
 * Date: 30/06/2007
 * Time: 11:08
 * 
 */

using System.Diagnostics;
using System.IO;
using System.Threading;
using Wax;
using NUnit.Framework;
using WatiN.Core;
using System;

namespace WaxLibTest
{
    /// <summary>
    /// Tests all of the behaviour of the <see cref="Command"/ > class.
    /// </summary>
    [TestFixture]
    public class CommandTest
    {
        #region Tests

        /// <summary>
        /// Tests the constructor initializes member fields correctly
        /// </summary>
        [Test]
        public void Constructor()
        {
            Command command = new Command();

            Assert.AreEqual(CommandType.None, command.CommandType, "Command type not initialized correctly");
            Assert.IsNotNull(command.FindMethod, "Command find method not initialized correctly");
            Assert.AreEqual(string.Empty, command.Id, "Id not initialized correctly");
            Assert.IsNotNull(command.Arguments, "Arguments not initialized correctly");
            Assert.AreEqual(0, command.Arguments.Count, "Arguments not initialized correctly");
        }



        /// <summary>
        /// Test the ClickNoWait command.
        /// </summary>
        [Test]
        public void ClickNoWait()
        {

            using (TestManager testManager = new TestManager())
            {
                testManager.Tests.Add(new Test());
                testManager.Tests[0].Commands.Add(CreateCommandGotoUrl(System.IO.Path.Combine(System.Environment.CurrentDirectory, "testpage1.htm")));
                testManager.Tests[0].Commands.Add(CommandFactory.Parse(new String[] { "CmdNoWait", "ClickNoWait", string.Empty, "ById", "linkDblClick" }));
                testManager.Execute();
            }
        }

        /// <summary>
        /// Test the SetCookie command.
        /// </summary>
        [Test]
        public void SetCookie()
        {

            using (TestManager testManager = new TestManager())
            {
                testManager.Tests.Add(new Test());
                testManager.Tests[0].Commands.Add(CreateCommandGotoUrl(System.IO.Path.Combine(System.Environment.CurrentDirectory, "testpage1.htm")));
                testManager.Tests[0].Commands.Add(CommandFactory.Parse(new String[] { "CmdSetCookie", "SetCookie", "http://www.google.co.uk/,\"wax=1234; expires=Wed, 01-Jan-2020 00:00:00 GMT\"", string.Empty, string.Empty }));
                testManager.Execute();

                Assert.AreEqual("wax=1234", testManager.Browser.GetCookie("http://www.google.co.uk/", "wax"));
            }
        }

        /// <summary>
        /// Tests the GetCookie command.
        /// </summary>
        [Test]
        public void GetCookie()
        {
            using (TestManager testManager = new TestManager())
            {
                testManager.Tests.Add(new Test());
                testManager.Tests[0].Commands.Add(CreateCommandGotoUrl(System.IO.Path.Combine(System.Environment.CurrentDirectory, "testpage1.htm")));
                testManager.Tests[0].Commands.Add(CommandFactory.Parse(new String[] { "CmdSetCookie", "SetCookie", "http://www.google.co.uk/,\"wax=1234; expires=Wed, 01-Jan-2020 00:00:00 GMT\"", string.Empty, string.Empty }));
                testManager.Tests[0].Commands.Add(CommandFactory.Parse(new String[] { "CmdGetCookie", "GetCookie", "\"http://www.google.co.uk/\",\"wax\"", string.Empty, string.Empty }));
                testManager.Execute();

                Assert.AreEqual("wax=1234", testManager.ExecutionContext.LastFoundValue, "GetCookie failed to retrieve the expected value.");
            }
        }

        /// <summary>
        /// Test that we can issue the screen shot command passing in the filename using the tilda syntax.
        /// </summary>
        [Test]
        public void ScreenshotWithTilda()
        {
            string tempImageFile = @"~\test1.png";

            using (TestManager testManager = new TestManager())
            {
                testManager.Tests.Add(new Test());
                testManager.Tests[0].Commands.Add(
                    CreateCommandGotoUrl(
                        System.IO.Path.Combine(System.Environment.CurrentDirectory, "testpage1.htm")));
                testManager.Tests[0].Commands.Add(
                    CommandFactory.Parse(
                        new String[] { "CmdScreenshot", "Screenshot", tempImageFile, string.Empty, string.Empty }));
                testManager.Execute();

                Assert.IsTrue(File.Exists(tempImageFile.Replace("~", Environment.CurrentDirectory)), string.Format("Image file {0} not found after executing the screen shot command.", tempImageFile.Replace("~", Environment.CurrentDirectory)));
            }
        }

        /// <summary>
        /// Test that we can issue the screen shot command.
        /// </summary>
        [Test]
        public void Screenshot()
        {
            string tempImageFile = Path.GetTempFileName();

            try
            {
                using (TestManager testManager = new TestManager())
                {
                    testManager.Tests.Add(new Test());
                    testManager.Tests[0].Commands.Add(
                        CreateCommandGotoUrl(
                            System.IO.Path.Combine(System.Environment.CurrentDirectory, "testpage1.htm")));
                    testManager.Tests[0].Commands.Add(
                        CommandFactory.Parse(
                            new String[] { "CmdScreenshot", "Screenshot", tempImageFile, string.Empty, string.Empty }));
                    testManager.Execute();

                    Assert.IsTrue(File.Exists(tempImageFile), "Image file not found after executing the screen shot command.");
                }
            }
            finally
            {
                if (File.Exists(tempImageFile))
                {
                    File.Delete(tempImageFile);
                }
            }
        }

        /// <summary>
        /// Test that we can issue the clear cookies command.
        /// </summary>
        [Test]
        public void ClearCookies()
        {
            using (TestManager testManager = new TestManager())
            {
                testManager.Tests.Add(new Test());
                testManager.Tests[0].Commands.Add(CommandFactory.Parse(new String[] { "ClearCookiesByDomain", "ClearCookies", string.Empty, string.Empty, string.Empty }));
                testManager.Tests[0].Commands.Add(CreateCommandGotoUrl(System.IO.Path.Combine(System.Environment.CurrentDirectory, "testpage1.htm")));
                testManager.Execute();

                Assert.IsFalse(IE.Exists(Find.ByTitle("Test page 1")));
            }
        }

        /// <summary>
        /// Test that we can issue the clear cookies command for a specific url.
        /// </summary>
        [Test]
        public void ClearCookiesByDomain()
        {
            using (TestManager testManager = new TestManager())
            {
                testManager.Tests.Add(new Test());
                testManager.Tests[0].Commands.Add(CommandFactory.Parse(new String[] { "ClearCookiesByDomain", "ClearCookies", "http://google.com", string.Empty, string.Empty }));
                testManager.Tests[0].Commands.Add(CreateCommandGotoUrl(System.IO.Path.Combine(System.Environment.CurrentDirectory, "testpage1.htm")));
                testManager.Execute();

                Assert.IsFalse(IE.Exists(Find.ByTitle("Test page 1")));
            }
        }

        /// <summary>
        /// Test that we can issue the clear cache command.
        /// </summary>
        [Test]
        public void ClearCache()
        {
            using (TestManager testManager = new TestManager())
            {
                testManager.Tests.Add(new Test());
                testManager.Tests[0].Commands.Add(CommandFactory.Parse(new String[] { "ClearCacheText", "ClearCache", string.Empty, string.Empty, string.Empty }));
                testManager.Tests[0].Commands.Add(CreateCommandGotoUrl(System.IO.Path.Combine(System.Environment.CurrentDirectory, "testpage1.htm")));
                testManager.Execute();

                Assert.IsFalse(IE.Exists(Find.ByTitle("Test page 1")));
            }
        }

        /// <summary>
        /// Test that we can issue the bring to front command.
        /// </summary>
        [Test]
        public void BringToFront()
        {
            using (TestManager testManager = new TestManager())
            {
                testManager.Tests.Add(new Test());
                testManager.Tests[0].Commands.Add(CreateCommandGotoUrl(System.IO.Path.Combine(System.Environment.CurrentDirectory, "testpage1.htm")));
                testManager.Tests[0].Commands.Add(CommandFactory.Parse(new String[] { "BringToFrontTest", "BringToFront", string.Empty, string.Empty, string.Empty }));
                testManager.Execute();

                Assert.IsTrue(IE.Exists(Find.ByTitle("Test page 1")));
            }
        }

        /// <summary>
        /// Tests the Focus command.
        /// </summary>
        [Test]
        public void Focus()
        {
            using (TestManager testManager = new TestManager())
            {
                testManager.Tests.Add(new Test());
                testManager.Tests[0].Commands.Add(CreateCommandGotoUrl(System.IO.Path.Combine(System.Environment.CurrentDirectory, "testpage1.htm")));
                testManager.Tests[0].Commands.Add(CommandFactory.Parse(new String[] { "FocusTest", "Focus", string.Empty, "ById", "chkEmailMe" }));
                testManager.Execute();
            }
        }

        /// <summary>
        /// Tests the PressTab command.
        /// </summary>
        [Test]
        public void PressTab()
        {
            using (TestManager testManager = new TestManager())
            {
                testManager.Tests.Add(new Test());
                testManager.Tests[0].Commands.Add(CreateCommandGotoUrl(System.IO.Path.Combine(System.Environment.CurrentDirectory, "testpage1.htm")));
                testManager.Tests[0].Commands.Add(CommandFactory.Parse(new String[] { "PressTabTest", "PressTab", string.Empty, string.Empty, string.Empty }));
                testManager.Execute();
            }
        }

        /// <summary>
        /// Test that we can refresh the current page.
        /// </summary>
        [Test]
        public void Refresh()
        {
            using (TestManager testManager = new TestManager())
            {
                testManager.Tests.Add(new Test());
                testManager.Tests[0].Commands.Add(CreateCommandGotoUrl(System.IO.Path.Combine(System.Environment.CurrentDirectory, "testpage1.htm")));
                testManager.Tests[0].Commands.Add(CommandFactory.Parse(new String[] { "RefreshTest", "Refresh", string.Empty, string.Empty, string.Empty }));
                testManager.Execute();
            }
        }

        /// <summary>
        /// Test that we can close the browser instance.
        /// </summary>
        [Test]
        public void Close()
        {
            using (TestManager testManager = new TestManager())
            {
                testManager.Tests.Add(new Test());
                testManager.Tests[0].Commands.Add(CreateCommandGotoUrl(System.IO.Path.Combine(System.Environment.CurrentDirectory, "testpage1.htm")));
                testManager.Tests[0].Commands.Add(CommandFactory.Parse(new String[] { "CloseTest", "Close", string.Empty, string.Empty, "Test page 1" }));
                testManager.Execute();

                Assert.IsFalse(IE.Exists(Find.ByTitle("Test page 1")));
            }
        }

        /// <summary>
        /// Tests the the ability to attach to an existing instance of internet explorer, and that
        /// after attaching we can execute subsequent commands against the attached internet explorer instance.
        /// </summary>
        [Test]
        public void AttachToIE()
        {
            Process.Start("iexplore.exe", System.IO.Path.Combine(System.Environment.CurrentDirectory, "testpage1.htm"));

            // Give IE a chance to load.
            Thread.Sleep(2000);

            using (TestManager testManager = new TestManager())
            {
                testManager.Tests.Add(new Test());
                testManager.Tests[0].Commands.Add(CommandFactory.Parse(new String[] { "AttachToIETest", "AttachToIE", string.Empty, "ByTitle", "Test page 1" }));
                testManager.Tests[0].Commands.Add(CreateCommandGotoUrl(System.IO.Path.Combine(System.Environment.CurrentDirectory, "testpage2.htm")));
                testManager.Execute();

                Assert.IsTrue(testManager.Browser.Url.EndsWith("testpage2.htm"), string.Format("Command.Execute using a goto did not navigate to the expected page: testpage2.htm, instead found :{0}", testManager.Browser.Url));
            }
        }

        /// <summary>
        /// Test that we can process a command against the last found element.
        /// </summary>
        [Test]
        public void LastElement()
        {
            using (TestManager testManager = new TestManager())
            {
                testManager.Tests.Add(new Test());
                testManager.Tests[0].Commands.Add(CreateCommandGotoUrl(System.IO.Path.Combine(System.Environment.CurrentDirectory, "testpage1.htm")));
                testManager.Tests[0].Commands.Add(SetValueCommandTest.CreateCommandText("Edward,Text", "ById", "FirstName"));
                testManager.Tests[0].Commands.Add(CommandFactory.Parse(new String[] { "ValidateLastElementTest", "Validate", "Edward,Value", "ByLastElement", string.Empty }));
                testManager.Tests[0].Commands.Add(CreateCommandGotoUrl(System.IO.Path.Combine(System.Environment.CurrentDirectory, "testpage2.htm")));
                testManager.Execute();

                Assert.IsTrue(testManager.Browser.Url.EndsWith("testpage2.htm"), string.Format("Command.Execute using a goto did not navigate to the expected page: testpage2.htm, instead found :{0}", testManager.Browser.Url));
            }
        }

        /// <summary>
        /// Tests the that if you attempt to attach to an instance of IE that can not be found an appropriate error is thrown.
        /// </summary>
        [Test, ExpectedException(typeof(FindMethodException))]
        public void AttachToIENoRunningInstanceFound()
        {
            using (TestManager testManager = new TestManager())
            {
                testManager.Tests.Add(new Test());
                testManager.Tests[0].Commands.Add(CommandFactory.Parse(new String[] { "AttachToIETest", "AttachToIE", string.Empty, "ByTitle", "Test page 23" }));
                testManager.Execute();

                Assert.IsTrue(testManager.Browser.Url.EndsWith("testpage2.htm"), "Command.Execute using a goto did not navigate to the expected page: testpage1.htm");
            }
        }

        /// <summary>
        /// Tests the execution of the goto command
        /// </summary>
        [Test]
        public void ExecuteGoto()
        {
            using (TestManager testManager = new TestManager())
            {
                testManager.Tests.Add(new Test());
                testManager.Tests[0].Commands.Add(CreateCommandGotoUrl(System.IO.Path.Combine(System.Environment.CurrentDirectory, "testpage1.htm")));
                testManager.Execute();

                Assert.IsTrue(testManager.Browser.Url.EndsWith("testpage1.htm"), "Command.Execute using a goto did not navigate to the expected page: testpage1.htm");
            }
        }

        /// <summary>
        /// Tests the execution of the goto command for a page that does not exist
        /// </summary>
        [Test, ExpectedException(typeof(ExecutionException))]
        public void ExecuteGotoInvalidUrl()
        {
            using (TestManager testManager = new TestManager())
            {
                testManager.Tests.Add(new Test());
                testManager.Tests[0].Commands.Add(CreateCommandGotoUrl(System.IO.Path.Combine(System.Environment.CurrentDirectory, "testpage1NotExist.htm")));
                testManager.Execute();

                Assert.IsTrue(testManager.Browser.Url.EndsWith("testpage1.htm"), "Command.Execute using a goto did not navigate to the expected page: testpage1.htm");
            }
        }

        /// <summary>
        /// Tests the execution of the click command
        /// </summary>
        [Test]
        public void ExecuteClick()
        {
            using (TestManager testManager = new TestManager())
            {
                testManager.Tests.Add(new Test());
                testManager.Tests[0].Commands.Add(CreateCommandGotoUrl(System.IO.Path.Combine(System.Environment.CurrentDirectory, "testpage1.htm")));
                testManager.Tests[0].Commands.Add(CreateCommandClick("ById", "link1"));

                testManager.Execute();

                Assert.IsTrue(testManager.Browser.Url.EndsWith("testpage2.htm"), "Command.Execute using a click did not navigate to the expected page: testpage2.htm");
            }
        }

        /// <summary>
        /// Tests the execution of the double click command
        /// </summary>
        [Test]
        public void ExecuteDoubleClick()
        {
            using (TestManager testManager = new TestManager())
            {
                testManager.Tests.Add(new Test());
                testManager.Tests[0].Commands.Add(CreateCommandGotoUrl(System.IO.Path.Combine(System.Environment.CurrentDirectory, "testpage1.htm")));
                testManager.Tests[0].Commands.Add(CreateCommandDoubleClick("ById", "linkDblClick"));

                testManager.Execute();

                Assert.AreEqual("ondblclick", testManager.Browser.Div("results").Text, "Command.Execute using a double click did work as expected.");
            }
        }

        /// <summary>
        /// Tests the execution of the back command
        /// </summary>
        [Test]
        public void ExecuteBack()
        {
            using (TestManager testManager = new TestManager())
            {
                testManager.Tests.Add(new Test());
                testManager.Tests[0].Commands.Add(CreateCommandGotoUrl(System.IO.Path.Combine(System.Environment.CurrentDirectory, "testpage1.htm")));
                testManager.Tests[0].Commands.Add(CreateCommandGotoUrl(System.IO.Path.Combine(System.Environment.CurrentDirectory, "testpage2.htm")));
                testManager.Tests[0].Commands.Add(CreateBackCommand());
                testManager.Execute();

                Assert.IsTrue(testManager.Browser.Url.EndsWith("testpage1.htm"), "Command.Execute using a click did not navigate to the expected page: testpage1.htm");
            }
        }

        /// <summary>
        /// Tests the execution of the flash command
        /// </summary>
        [Test]
        public void ExecuteFlash()
        {
            using (TestManager testManager = new TestManager())
            {
                testManager.Tests.Add(new Test());
                testManager.Tests[0].Commands.Add(CreateCommandGotoUrl(System.IO.Path.Combine(System.Environment.CurrentDirectory, "testpage1.htm")));
                testManager.Tests[0].Commands.Add(CommandFactory.Parse(new String[] { "FlashTest", "Flash", string.Empty, "ByNameAndValue", "radio1,2" }));
                testManager.Execute();
            }
        }

        /// <summary>
        /// Tests the execution of the back command
        /// </summary>
        [Test]
        public void ExecuteForward()
        {
            using (TestManager testManager = new TestManager())
            {
                testManager.Tests.Add(new Test());
                testManager.Tests[0].Commands.Add(CreateCommandGotoUrl(System.IO.Path.Combine(System.Environment.CurrentDirectory, "testpage1.htm")));
                testManager.Tests[0].Commands.Add(CreateCommandGotoUrl(System.IO.Path.Combine(System.Environment.CurrentDirectory, "testpage2.htm")));
                testManager.Tests[0].Commands.Add(CreateBackCommand());
                testManager.Tests[0].Commands.Add(CreateForwardCommand());
                testManager.Execute();

                Assert.IsTrue(testManager.Browser.Url.EndsWith("testpage2.htm"), "Command.Execute using a click did not navigate to the expected page: testpage1.htm");
            }
        }

        #endregion

        #region Private static methods

        /// <summary>
        /// Creates a command that navigates to a url
        /// </summary>
        /// <returns>A command that navigates to a url</returns>
        internal static Command CreateCommandGotoUrl(string url)
        {
            return CommandFactory.Parse(new string[] { "GotoTestPage", "Goto", url, null, null });
        }

        /// <summary>
        /// Creates a command that navigates to the previous page in the browser's history.
        /// </summary>
        /// <returns>A command that navigates to the previous page in the browser's history</returns>
        internal static Command CreateBackCommand()
        {
            return CommandFactory.Parse(new string[] { "GotoTestPage", "Back", null, null, null });
        }

        /// <summary>
        /// Creates a command that navigates forward in the browser's history.
        /// </summary>
        /// <returns>A command that navigates foward in the browser's history</returns>
        internal static Command CreateForwardCommand()
        {
            return CommandFactory.Parse(new string[] { "GotoTestPage", "Forward", null, null, null });
        }

        /// <summary>
        /// Creates a command that clicks a link for the given id
        /// </summary>
        /// <param name="findByMethod">Find by method name</param>
        /// <param name="findByMethodArgs">Arguments to pass to the find method</param>
        /// <returns>A command that clicks a link for the given id</returns>
        internal static Command CreateCommandClick(string findByMethod, string findByMethodArgs)
        {
            return CommandFactory.Parse(new string[] { "GotoTestPage", "Click", null, findByMethod, findByMethodArgs });
        }

        /// <summary>
        /// Creates a command that clicks a link for the given id
        /// </summary>
        /// <param name="findByMethod">Find by method name</param>
        /// <param name="findByMethodArgs">Arguments to pass to the find method</param>
        /// <returns>A command that clicks a link for the given id</returns>
        internal static Command CreateCommandDoubleClick(string findByMethod, string findByMethodArgs)
        {
            return CommandFactory.Parse(new string[] { "SomeLink", "DoubleClick", null, findByMethod, findByMethodArgs });
        }

        #endregion
    }
}
